#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>


#define SIZE 512
#define ZERO '\0'
#define SEP " "
#define NUM 32
#define SkipPath(p) do { p += (strlen(p)-1); while(*p != '/' )p--; }while(0)


char cwd[SIZE*2];
char* gArgv[NUM];
int lastcode = 0;

void Die()
{
    exit(1);
}

const char* GetHome()
{
    const char* Home = getenv("HOME");
    if(Home == NULL) return "/";
    return Home;
}

const char* GetUserName()
{
    const char* UserName = getenv("USER");
    if(UserName == NULL) return "NoneName";
    return UserName;
}

const char* GetHonstName()
{
    const char* HonstName = getenv("HOSTNAME");
    if(HonstName == NULL) return "NoneHost";
    return HonstName;
}

//路径
const char* GetCwd()
{
    const char* Cwd = getenv("PWD");
    //TODO

    if(Cwd == NULL) return "NoneCwd";
    return Cwd;
}

//CommandLine : output
void MakeCommandLine()
{
    char line[SIZE];
    const char* UserName = GetUserName();
    const char* HonstName = GetHonstName();
    const char* Cwd = GetCwd();
    SkipPath(Cwd);

    snprintf(line,sizeof(line),"[%s@%s %s]~ ",UserName,HonstName,strlen(Cwd)==1?"/":Cwd+1);

    printf("%s",line);
    fflush(stdout);
}

int GetUserCommand(char UserCommand[],size_t n)
{
    char* s = fgets(UserCommand,n,stdin);
    if(s==NULL)return -1;
    UserCommand[strlen(UserCommand)-1] = ZERO;
    return strlen(UserCommand);
}

void SplitComman(char command[],size_t n)
{
    gArgv[0] = strtok(command,SEP);
    int index = 1;
    while((gArgv[index++] = strtok(NULL,SEP)));//这样最后不能分割时让argv最后一个元素是NULL
    return;
}

void ExecuteCommand()
{
    pid_t id = fork();
    if(id<0)Die();
    else if(id==0)
    {
        //child
        execvp(gArgv[0],gArgv);
        exit(errno);
    }
    else
    {
        //father
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)
        {
            lastcode = WEXITSTATUS(status);
            if(lastcode!=0)printf("%s:%s:%d\n",gArgv[0],strerror(lastcode),lastcode);
        }
    }
}

void Cd()
{
    const char* path = gArgv[1];
    if(path==NULL) path=GetHome();
    chdir(path);

    //更新环境变量
    char tmp[SIZE*2];
    getcwd(tmp,sizeof(tmp));
    snprintf(cwd,sizeof(cwd),"PWD=%s",tmp);
    putenv(cwd);
}

int CheckBuilding()
{
    int yes = 0;
    const char* enter_cmd = gArgv[0];
    if(strcmp(enter_cmd,"cd")==0)
    {
        yes = 1;
        Cd();
    }
    else if(strcmp(enter_cmd,"echo") == 0 && strcmp(gArgv[1],"$?") == 0)
    {
        yes = 1;
        printf("%d\n",lastcode);
        lastcode = 0;
    }

    return yes;
}

int main()
{
    int quit = 0;
    while(!quit)
    {
        //1,自己输出命令行
        MakeCommandLine();

        //2.获取用户命令字符串
        char UserCommand[SIZE];
        int n = GetUserCommand(UserCommand,sizeof(UserCommand));
        if(n<=0)return 1;

        //3.命令行字符串分割
        SplitComman(UserCommand,sizeof(UserCommand));

        //4.检查是否为内建命令
        n = CheckBuilding(); 
        if(n) continue;

        //n.执行命令
        ExecuteCommand();
    }


    return 0;
}
